/*//GEN-LINE:initComponents
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.ihmproject.treewindow;

import org.ihmproject.voletEdition.*;
import java.awt.BorderLayout;
import java.awt.Point;
import java.util.*;
import java.awt.Rectangle;
import java.awt.geom.Line2D;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
import java.util.logging.Logger;
import org.ihmproject.voletEdition.voletEditionTopComponent;
import org.netbeans.api.visual.action.ActionFactory;
import org.netbeans.api.visual.action.EditProvider;
import org.netbeans.api.visual.action.MoveProvider;
import org.netbeans.api.visual.action.RectangularSelectProvider;
import org.netbeans.api.visual.action.SelectProvider;
import org.netbeans.api.visual.action.TwoStateHoverProvider;
import org.netbeans.api.visual.action.WidgetAction;
import org.netbeans.api.visual.anchor.AnchorFactory;
import org.netbeans.api.visual.graph.GraphScene;
import org.netbeans.api.visual.graph.layout.*;
import org.netbeans.api.visual.layout.LayoutFactory;
import org.netbeans.api.visual.widget.ConnectionWidget;
import org.netbeans.api.visual.widget.LabelWidget;
import org.netbeans.api.visual.widget.LayerWidget;
import org.netbeans.api.visual.widget.Widget;
import org.netbeans.api.visual.widget.general.IconNodeWidget;
import org.openide.util.NbBundle;
import org.openide.util.Lookup;
import org.netbeans.api.visual.graph.layout.GraphLayoutFactory;
import org.netbeans.api.visual.graph.layout.GraphLayoutSupport;
import org.netbeans.api.visual.layout.SceneLayout;
import org.netbeans.api.visual.widget.Scene;
import org.openide.nodes.Node;
import org.openide.util.ImageUtilities;
import org.openide.windows.Mode;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;

/**
 * Top component which displays something.
 */
public final class FenetreArbreTopComponent extends TopComponent implements Lookup.Provider {

    private static FenetreArbreTopComponent instance;
    /** path to the icon used by the component and its open action */
//    static final String ICON_PATH = "SET/PATH/TO/ICON/HERE";
    private static final String PREFERRED_ID = "FenetreArbreTopComponent";
    public DemoGraphScene scene;

    public FenetreArbreTopComponent() {
        initComponents();
        setAutoscrolls(true);
        setName(NbBundle.getMessage(FenetreArbreTopComponent.class, "CTL_FenetreArbreTopComponent"));
        setToolTipText(NbBundle.getMessage(FenetreArbreTopComponent.class, "HINT_FenetreArbreTopComponent"));

        scene = new DemoGraphScene();

        add(scene.createView(), BorderLayout.CENTER);

        Widget widget = addRootNode(scene.HELLO_NODE_ID, scene.HELLO_NODE_ID, "Abstraite");

        setActivatedNodes(new Node[]{((MyIconNodeWidget) widget).node});

//        setIcon(Utilities.loadImage(ICON_PATH, true));
    }

    public Widget addRootNode(String nodeID, String nom, String type) {
        scene.nom = nom;
        scene.type = type;
        scene.plateformes = new Vector<String>();
        scene.operateur = "Aucun";
        Widget node = scene.addNode(nodeID);
        this.validate();
        scene.layoutScene();
        return node;
    }

    public Widget addNode(String nodeID, String nom, String parentID,
            String edge, String type, Vector<String> plateformes,
            Vector<String> decoration, String precondition, String operateur,
            MyIconNodeWidget parent) {

        scene.nom = nom;
        scene.type = type;
        scene.plateformes = plateformes;
        scene.decoration = decoration;
        scene.precondition = precondition;
        scene.operateur = operateur;
        scene.ajoutOp = false;
        scene.parent = parent;


        Widget node = scene.addNode(nodeID);

        scene.addEdge(edge);
        scene.setEdgeSource(edge, parentID);
        scene.setEdgeTarget(edge, nodeID);

        scene.validate();
        scene.layoutScene();


        Node[] nd = getActivatedNodes();
        Node[] nv = new Node[nd.length+1];
        for (int i=0;i<nd.length;i++) {
            nv[i] = nd[i];
        }
        nv[nd.length] = ((MyIconNodeWidget)node).node;
        setActivatedNodes(nv);

        return node;

    }

    public void removeNode(String nodeID) {

        // Supprimer les fils egalements

        scene.removeNodeWithEdges(nodeID);
        scene.validate();
    }

    public void addOperator(String edge, String operateur, String node1, String node2) {
        scene.ajoutOp = true;
        scene.operateur = operateur;
        scene.IDEgdeOp = edge;
        scene.source = node1;
        scene.target = node2;
        scene.addEdge(edge);
        scene.attachEdgeSourceAnchor(edge, null, node1);
        scene.attachEdgeTargetAnchor(edge, null, node2);
        scene.validate();
        scene.layoutScene();
    }

    public void hideSubTree(String node) {
        // verifier si pas deja caché puis cacher tous les widgets fils si pas deja visible
    }

    public void showSubTree(String node) {
        // verifier si pas deja visible puis montrer tous les widgets fils
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        setLayout(new java.awt.BorderLayout());
    }// </editor-fold>                        


    // Variables declaration - do not modify                     
    // End of variables declaration                   
    /**
     * Gets default instance. Do not use directly: reserved for *.settings files only,
     * i.e. deserialization routines; otherwise you could get a non-deserialized instance.
     * To obtain the singleton instance, use {@link #findInstance}.
     */
    public static synchronized FenetreArbreTopComponent getDefault() {
        if (instance == null) {
            instance = new FenetreArbreTopComponent();
        }
        return instance;
    }

    /**
     * Obtain the FenetreArbreTopComponent instance. Never call {@link #getDefault} directly!
     */
    public static synchronized FenetreArbreTopComponent findInstance() {
        TopComponent win = WindowManager.getDefault().findTopComponent(PREFERRED_ID);
        if (win == null) {
            Logger.getLogger(FenetreArbreTopComponent.class.getName()).warning(
                    "Cannot find " + PREFERRED_ID + " component. It will not be located properly in the window system.");
            return getDefault();
        }
        if (win instanceof FenetreArbreTopComponent) {
            return (FenetreArbreTopComponent) win;
        }
        System.out.println("There seem to be multiple components with the '" + PREFERRED_ID +
                "' ID. That is a potential source of errors and unexpected behavior.");
        return getDefault();
    }

    @Override
    public int getPersistenceType() {
        return TopComponent.PERSISTENCE_ALWAYS;
    }

    @Override
    public void componentOpened() {
    }

    @Override
    public void componentClosed() {
        // TODO add custom code on component closing
    }

    /** replaces this in object stream */
    @Override
    public Object writeReplace() {
        return new ResolvableHelper();
    }

    @Override
    protected String preferredID() {
        return PREFERRED_ID;
    }

    final static class ResolvableHelper implements Serializable {

        private static final long serialVersionUID = 1L;

        public Object readResolve() {
            return FenetreArbreTopComponent.getDefault();
        }
    }

    public class DemoGraphScene extends GraphScene<String, String> {

        private LayerWidget mainLayer;
        private LayerWidget connectionLayer;
        private LayerWidget backgroundLayer;
        SceneLayout sceneLayout;
        private WidgetAction moveAction = ActionFactory.createMoveAction(null, new MultiMoveProvider());
        private WidgetAction hoverAction = ActionFactory.createHoverAction(new TwoStateHoverProvider() {

            public void unsetHovering(Widget w) {
                w.getChildren().get(2).setVisible(false);
            }

            public void setHovering(Widget w) {
                w.getChildren().get(2).setVisible(true);
            }
        });
        public static final String HELLO_NODE_ID = "Root";
        public String type;
        public Vector<String> plateformes;
        public Vector<String> decoration = new Vector();
        public String precondition;
        private String nom;
        private boolean ajoutOp;
        private String operateur;
        private String source;
        private String target;
        private MyIconNodeWidget parent;
        private String IDEgdeOp;

        public DemoGraphScene() {

            this.setMaximumBounds(new Rectangle(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE));
            addChild(backgroundLayer = new LayerWidget(this));
            addChild(mainLayer = new LayerWidget(this));
            addChild(connectionLayer = new LayerWidget(this));

            getActions().addAction(ActionFactory.createZoomAction());
            getActions().addAction(ActionFactory.createPanAction());
            getActions().addAction(ActionFactory.createRectangularSelectAction(ActionFactory.createDefaultRectangularSelectDecorator((Scene) this), backgroundLayer, new RectangularSelectProvider() {

                public void performSelection(Rectangle sceneSelection) {
                    boolean entirely = sceneSelection.width > 0;
                    int w = sceneSelection.width;
                    int h = sceneSelection.height;
                    Rectangle rect = new Rectangle(w >= 0 ? 0 : w, h >= 0 ? 0 : h, w >= 0 ? w : -w, h >= 0 ? h : -h);
                    rect.translate(sceneSelection.x, sceneSelection.y);

                    HashSet<Object> set = new HashSet<Object>();
                    Set<?> objects = scene.getObjects();
                    for (Object object : objects) {
                        Widget widget = scene.findWidget(object);
                        if (widget == null) {
                            continue;
                        }
                        if (entirely) {
                            Rectangle widgetRect = widget.convertLocalToScene(widget.getBounds());
                            if (rect.contains(widgetRect)) {
                                set.add(object);
                            }
                        } else {
                            if (widget instanceof ConnectionWidget) {
                                ConnectionWidget conn = (ConnectionWidget) widget;
                                java.util.List<Point> points = conn.getControlPoints();
                                for (int i = points.size() - 2; i >= 0; i--) {
                                    Point p1 = widget.convertLocalToScene(points.get(i));
                                    Point p2 = widget.convertLocalToScene(points.get(i + 1));
                                    if (new Line2D.Float(p1, p2).intersects(rect)) {
                                        set.add(object);
                                    }
                                }
                            } else {
                                Rectangle widgetRect = widget.convertLocalToScene(widget.getBounds());
                                if (rect.intersects(widgetRect)) {
                                    set.add(object);
                                }
                            }
                        }
                    }
                    Iterator<Object> iterator = set.iterator();
                    if (!iterator.hasNext()) {
                        Mode mod = WindowManager.getDefault().findMode(FenetreArbreTopComponent.findInstance());
                        FenetreArbreTopComponent fatc = (FenetreArbreTopComponent) mod.getSelectedTopComponent();
                        ((MyNode)fatc.getActivatedNodes()[0]).fire(false);
                    }
                    if (set.size() == 1) {
                        Mode mod = WindowManager.getDefault().findMode(FenetreArbreTopComponent.findInstance());
                        FenetreArbreTopComponent fatc = (FenetreArbreTopComponent) mod.getSelectedTopComponent();
                        Object obj = iterator.next();
                        System.out.println(findWidget(obj));
                        if (findWidget(obj) instanceof MyIconNodeWidget) {
                            fatc.setActivatedNodes(new Node[] { ((MyIconNodeWidget)findWidget(obj)).node });
                            ((MyIconNodeWidget)findWidget(obj)).node.fire(true);
                        }
                    }
                    scene.setFocusedObject(iterator.hasNext() ? iterator.next() : null);
                    scene.userSelectionSuggested(set, false);

                }
            }));
            getActions().addAction(hoverAction);

            GraphLayout<String, String> tgl = GraphLayoutFactory.createTreeGraphLayout(400, 50, 50, 50, true);
            GraphLayoutSupport.setTreeGraphLayoutRootNode(tgl, HELLO_NODE_ID);
            sceneLayout = LayoutFactory.createSceneGraphLayout(this, tgl);

            getActions().addAction(ActionFactory.createEditAction(new EditProvider() {

                public void edit(Widget widget) {
                    sceneLayout.invokeLayoutImmediately();
                }
            }));

        }

        public void layoutScene() {
            sceneLayout.invokeLayoutImmediately();
        }

        protected Widget attachNodeWidget(String node) {

            Widget parentWidget = new Widget(this);
            //parentWidget.setLayout(LayoutFactory.createHorizontalFlowLayout());

            MyIconNodeWidget widget = new MyIconNodeWidget(this);
            widget.setImage(ImageUtilities.loadImage("org/ihmproject/treewindow/" + type + ".png")); // NOI18N


            parentWidget.addChild(widget);

            Widget lw0 = new Widget(this);
            lw0.setLayout(LayoutFactory.createHorizontalFlowLayout());
            //lw0.getActions ().addAction (createSelectAction());
            //lw0.getActions ().addAction (moveAction);

            if (plateformes != null) {
                IconNodeWidget lw1 = new IconNodeWidget(this);
                lw1.setImage(ImageUtilities.loadImage("org/ihmproject/treewindow/PC.png"));
                lw1.setVisible(false);
                lw1.setToolTipText("PC");
                IconNodeWidget lw2 = new IconNodeWidget(this);
                lw2.setImage(ImageUtilities.loadImage("org/ihmproject/treewindow/PDA.png"));
                lw2.setVisible(false);
                lw2.setToolTipText("PDA");
                IconNodeWidget lw3 = new IconNodeWidget(this);
                lw3.setImage(ImageUtilities.loadImage("org/ihmproject/treewindow/Portable.png"));
                lw3.setVisible(false);
                lw3.setToolTipText("Mobile");
                IconNodeWidget lw4 = new IconNodeWidget(this);
                lw4.setImage(ImageUtilities.loadImage("org/ihmproject/treewindow/Vocal.png"));
                lw4.setVisible(false);
                lw4.setToolTipText("Vocale");

                lw0.addChild(lw1);
                lw0.addChild(lw2);
                lw0.addChild(lw3);
                lw0.addChild(lw4);

            }

            lw0.setVisible(false);

            widget.addChild(lw0);

            widget.getActions().addAction(ActionFactory.createSelectAction(new SelectProvider() {

                public boolean isAimingAllowed(Widget arg0, Point arg1, boolean arg2) {
                    return false;
                }

                public boolean isSelectionAllowed(Widget widget, Point arg1, boolean arg2) {
                    if (findObject(widget) != null) {
                        ((MyIconNodeWidget) widget).node.fire(true);
                        return true;
                    } else {
                        System.out.println("unselect");
                        //((MyIconNodeWidget)widget).fire(true);
                        return false;
                    }


                }

                public void select(Widget widget, Point arg1, boolean invertSelection) {
                    Object object = findObject(widget);
                    setFocusedObject(object);
                    setActivatedNodes(new Node[] {((MyIconNodeWidget)widget).node} );
                    if (object != null) {
                        if (!invertSelection && getSelectedObjects().contains(object)) {
                            return;
                        }
                        userSelectionSuggested(Collections.singleton(object), invertSelection);
                    } else {
                        userSelectionSuggested(Collections.emptySet(), invertSelection);
                    }
                }
            }));
            widget.getActions().addAction(moveAction);
            widget.getActions().addAction(hoverAction);
            widget.getActions().addAction(ActionFactory.createEditAction(voletEditionTopComponent.findInstance()));

            mainLayer.addChild(parentWidget);

            widget.setLabel(nom);
            widget.setID(node);
            widget.setType(type); // NOI18N
            widget.setTaskName(nom);
            widget.setPlateforme(plateformes);
            widget.setDecoration(decoration);
            widget.setParent(parent);
            widget.setOperateur(operateur);
            widget.setPreCondition(precondition);

            return widget;

        }

        protected Widget attachEdgeWidget(String edge) {
            if (!ajoutOp) {
                ConnectionWidget connection = new ConnectionWidget(this);
                connectionLayer.addChild(connection);
                return connection;
            } else {
                ConnectionWidget connection = new ConnectionWidget(this);
                LabelWidget label = new LabelWidget(this);
                label.setLabel(operateur);
                connection.addChild(label);
                connection.setConstraint(label, LayoutFactory.ConnectionWidgetLayoutAlignment.TOP_CENTER, 0.5f);
                connection.setVisible(false);
                connectionLayer.addChild(connection);

                return connection;
            }
        }

        protected void attachEdgeSourceAnchor(String edge, String oldSourceNode, String sourceNode) {
            Widget w = sourceNode != null ? findWidget(sourceNode) : null;
            ((ConnectionWidget) findWidget(edge)).setSourceAnchor(AnchorFactory.createRectangularAnchor(w));
        }

        protected void attachEdgeTargetAnchor(String edge, String oldTargetNode, String targetNode) {
            Widget w = targetNode != null ? findWidget(targetNode) : null;
            ((ConnectionWidget) findWidget(edge)).setTargetAnchor(AnchorFactory.createRectangularAnchor(w));
        }

        private class MultiMoveProvider implements MoveProvider {

            private HashMap<Widget, Point> originals = new HashMap<Widget, Point>();
            private Point original;

            public void movementStarted(Widget widget) {
                Object object = findObject(widget);
                if (isNode(object)) {
                    for (Object o : getSelectedObjects()) {
                        if (isNode(o)) {
                            Widget w = findWidget(o);
                            if (w != null) {
                                originals.put(w, w.getPreferredLocation());
                            }
                        }
                    }
                } else {
                    originals.put(widget, widget.getPreferredLocation());
                }
            }

            public void movementFinished(Widget widget) {
                originals.clear();
                original = null;
            }

            public Point getOriginalLocation(Widget widget) {
                original = widget.getPreferredLocation();
                return original;
            }

            public void setNewLocation(Widget widget, Point location) {
                int dx = location.x - original.x;
                int dy = location.y - original.y;
                for (Map.Entry<Widget, Point> entry : originals.entrySet()) {
                    Point point = entry.getValue();
                    entry.getKey().setPreferredLocation(new Point(point.x + dx, point.y + dy));
                }
            }
        }
    }
}
